package com.nuanshui.heatedloan.extension.shiro;

import java.io.Serializable;
import java.util.List;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.DisabledAccountException;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.SimplePrincipalCollection;
import org.apache.shiro.util.ByteSource;

import com.nuanshui.heatedloan.dal.IdTypeHandler;
import com.nuanshui.heatedloan.entity.cms.security.User;
import com.nuanshui.heatedloan.entity.cms.security.UserRole;
import com.nuanshui.heatedloan.service.cms.security.UserRoleService;
import com.nuanshui.heatedloan.service.cms.security.AdminUserService;
import com.nuanshui.heatedloan.util.Digests;
import com.nuanshui.heatedloan.util.Encodes;

/**
 * Shiro的服务类，用于登陆验证，授权
 * 
 */
public class ShiroDbRealm extends AuthorizingRealm {
	private static final int INTERATIONS = 1024;
	private static final int SALT_SIZE = 8;
	private static final String ALGORITHM = "SHA-1";

	protected AdminUserService userService;

	protected UserRoleService userRoleService;
	
	//验证密码的
	protected CredentialsMatcher credentialsMatcher;

	/**
	 * 给ShiroDbRealm提供编码信息，用于密码密码比对 描述
	 */
	public ShiroDbRealm() {
		super();
		final HashedCredentialsMatcher matcher = new HashedCredentialsMatcher(
				ALGORITHM);
		matcher.setHashIterations(INTERATIONS);
		setCredentialsMatcher(matcher);
	}

	/**
	 * 认证回调函数, 登录时调用.
	 */
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(
			final AuthenticationToken authcToken)
			throws AuthenticationException {
		final CaptchaUsernamePasswordToken token = (CaptchaUsernamePasswordToken) authcToken;
		final String parm = token.getCaptcha();
		final String c = (String) SecurityUtils.getSubject().getSession()
				.getAttribute(SimpleCaptchaServlet.CAPTCHA_KEY);
		// 验证码错误
		if (!parm.equalsIgnoreCase(c)) {
			throw new IncorrectCaptchaException("验证码错误！");
		}
		final User user = userService.getFrontUserByPhone(token.getUsername());
		if (user != null) {
			if (user.getStatus().equals("disabled")) {
				// 账号冻结
				throw new DisabledAccountException();
			}
			final byte[] salt = Encodes.decodeHex(user.getSalt());
			final ShiroUser shiroUser = new ShiroUser(user.getId(),
					user.getUsername(), user, user.getMuseumId());
			return new SimpleAuthenticationInfo(shiroUser, user.getPassword(),
					ByteSource.Util.bytes(salt), getName());
		} else {
			return null;
		}

	}
	
	//使用自定义的密码校验
	@Override
	public CredentialsMatcher getCredentialsMatcher(){
		return this.credentialsMatcher;
	}

	/**
	 * 授权查询回调函数, 进行鉴权但缓存中无用户的授权信息时调用.
	 */
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(
			final PrincipalCollection principals) {
		final ShiroUser shiroUser = (ShiroUser) principals.fromRealm(getName())
				.iterator().next();
		final List<UserRole> userRoles = userRoleService
				.find(shiroUser.getId());
		shiroUser.getUser().setUserRoles(userRoles);

		if (!userRoles.isEmpty()) {
			final SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
			for (final UserRole userRole : userRoles) {
				// 基于Permission的权限信息
				info.addStringPermissions(userRole.getRole()
						.getPermissionList());
			}
			return info;
		} else {
			return null;
		}
	}

	public static class HashPassword {
		public String salt;
		public String password;
	}

	/**
	 * 加密
	 */
	public HashPassword encrypt(final String plainText) {
		final HashPassword result = new HashPassword();
		final byte[] salt = Digests.generateSalt(SALT_SIZE);
		result.salt = Encodes.encodeHex(salt);
		final byte[] hashPassword = Digests.sha1(plainText.getBytes(), salt,
				INTERATIONS);
		result.password = Encodes.encodeHex(hashPassword);
		return result;

	}

	/**
	 * 判断密码是否正确
	 * 
	 * @param rePassword
	 *            用户输入的密码
	 * @param password
	 *            数据库中存放的密码
	 * @param salt
	 *            因子
	 * @return true 正确，false 不正确
	 */
	public static boolean decode(final String rePassword,
			final String password, final String salt) {
		final byte[] saltByte = Encodes.decodeHex(salt);
		final byte[] hashPassword = Digests.sha1(rePassword.getBytes(),
				saltByte, ShiroDbRealm.INTERATIONS);
		final String passwordCode = Encodes.encodeHex(hashPassword);
		if (password.equals(passwordCode)) {
			return true;
		}
		return false;
	}

	/**
	 * 更新指定用户授权信息缓存.
	 */
	public void clearCachedAuthorizationInfo(final String principal) {
		final SimplePrincipalCollection principals = new SimplePrincipalCollection(
				principal, getName());
		clearCachedAuthorizationInfo(principals);
	}

	public void setUserService(final AdminUserService userService) {
		this.userService = userService;
	}

	/**
	 * 设置 userRoleService 的值
	 * 
	 * @param userRoleService
	 */
	public void setUserRoleService(final UserRoleService userRoleService) {
		this.userRoleService = userRoleService;
	}

	
	public void setcredentialsMatcher(CredentialsMatcher credentialsMatcher){
		this.credentialsMatcher  = credentialsMatcher;
	}
	/**
	 * 自定义Authentication对象，使得Subject除了携带用户的登录名外还可以携带更多信息.
	 */
	public static class ShiroUser implements Serializable {
		
		private static final long serialVersionUID = -1748602382963711884L;
		private Long id;
		private String loginName;
		private User user;
		private String museumId;
		
		

		public ShiroUser() {

		}

		/**
		 * 构造函数
		 */
		public ShiroUser(final Long id, final String loginName, final User user, final String museumId) {
			this.id = id;
			this.loginName = loginName;
			this.user = user;
			this.museumId = museumId;
		}

		/**
		 * 返回 id 的值
		 */
		public Long getId() {
			return id;
		}

		/**
		 * 返回 loginName 的值
		 */
		public String getLoginName() {
			return loginName;
		}
		
		/**
		 * 获取当前用户可以管理的展馆id
		 * @author Gonzo
		 * @date 2017年1月12日下午3:34:42
		 * @return
		 * @since 1.0.0
		 */
		public String getMuseumId() {
			if(museumId == null || museumId.equals("-1")) return null;
			
			return IdTypeHandler.encode(Long.parseLong(museumId));
		}

		/**
		 * 返回 user 的值
		 */
		public User getUser() {
			return user;
		}

		/**
		 * 本函数输出将作为默认的<shiro:principal/>输出.
		 */
		@Override
		public String toString() {
			return loginName;
		}
		
		
	}
	
	
}
